package com.googlecode.perfectable.messageable;

import static com.google.common.base.Preconditions.checkState;

import java.util.Set;

import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.namespace.QName;

import com.google.common.collect.BiMap;
import com.google.common.collect.ImmutableBiMap;

class MessageQualifier {
	private final BiMap<QName, Class<? extends Message>> messageClasses;

	public static MessageQualifier create(Set<Class<? extends Message>> knownClasses) {
		BiMap<QName, Class<? extends Message>> messageClasses = createMessageClassesMap(knownClasses);
		return new MessageQualifier(messageClasses);
	}

	private MessageQualifier(BiMap<QName, Class<? extends Message>> messageClasses) {
		this.messageClasses = messageClasses;
	}

	public Class<? extends Message> classForName(QName name) throws UnknownMessageException {
		Class<? extends Message> messageClass = this.messageClasses.get(name);
		if(messageClass == null) {
			throw UnknownMessageException.ofName(name);
		}
		return messageClass;
	}

	public QName nameForClass(Class<? extends Message> messageClass) throws UnknownMessageException {
		QName messageName = this.messageClasses.inverse().get(messageClass);
		if(messageName == null) {
			throw UnknownMessageException.ofName(messageName);
		}
		return messageName;
	}

	private static BiMap<QName, Class<? extends Message>> createMessageClassesMap(
			Set<Class<? extends Message>> messageClasses) {
		ImmutableBiMap.Builder<QName, Class<? extends Message>> messageNamesBuilder = ImmutableBiMap.builder();
		for(Class<? extends Message> messageClass : messageClasses) {
			XmlRootElement elementAnnotation = messageClass.getAnnotation(XmlRootElement.class);
			checkState(elementAnnotation != null, "Message class %s is not annotated with XmlRootElement", messageClass);
			QName name = new QName(elementAnnotation.namespace(), elementAnnotation.name());
			messageNamesBuilder.put(name, messageClass);
		}
		return messageNamesBuilder.build();
	}

}
